from ttkbootstrap.constants import *
from ttkbootstrap.dialogs.dialogs import Messagebox
from socket import *
from create_sign import *
from ttkbootstrap.scrolled import ScrolledText
from tkinter.filedialog import askopenfilename
import time
import pymysql
import ttkbootstrap as ttk


class ClientPage:
    def __init__(self, master=None, cilent=None):
        self.cilent = cilent
        self.root = master
        self.root.minsize(800, 650)
        self.page1 = ttk.Frame(self.root)
        self.page2 = ttk.Frame(self.root)
        self.username = ttk.StringVar()
        self.password = ttk.StringVar()
        self.d1 = ttk.StringVar()
        self.P1 = ttk.StringVar()
        self.RS = ttk.StringVar()
        self.filepath = ttk.StringVar()
        self.message_box_label = None  # 交互窗口展示的信息
        self.file_box_label = None
        self.response = None
        self.tcp_socket_1 = None
        self.var = ttk.IntVar()
        self.message = ['测试文件', 12345678]
        self.loginpage()

    def loginpage(self):
        self.page1.pack(fill=X, padx=20)

        title_label = ttk.Label(self.page1, text="欢迎使用\n基于协同签名的分布式SM2数字签名系统",
                                font=("楷体", 20), justify="center")
        title_label.pack(side=TOP, pady=(120, 80))

        username_frame = ttk.Frame(self.page1)
        username_label = ttk.Label(username_frame, text="用户名:", width=6)
        username_label.pack(side=LEFT, padx=5, pady=5)
        username_entry = ttk.Entry(username_frame, textvariable=self.username, width=30)
        username_entry.pack(side=RIGHT, padx=5, pady=5)
        username_frame.pack(pady=(0, 10), side=TOP)

        password_frame = ttk.Frame(self.page1)
        password_label = ttk.Label(password_frame, text="密   码:", width=6)
        password_label.pack(side=LEFT, fill=X, padx=5, pady=5)
        password_entry = ttk.Entry(password_frame, textvariable=self.password, width=30)
        password_entry.pack(side=RIGHT, padx=5, pady=5)
        password_frame.pack(pady=(0, 10), side=TOP)

        login_button = ttk.Button(self.page1, text="登录系统", command=self.login_check)
        login_button.pack(padx=5, pady=5)

    def login_check(self):
        username = self.username.get()
        password = self.password.get()
        self.connect_mysql(username, password)
        if self.response:
            self.page1.destroy()
            self.main_page()
            print(username)
        else:
            Messagebox.show_warning(title='错误', message='账号或密码错误！')

    def connect_mysql(self, username, password):
        conn = pymysql.connect(
            host='bj-cynosdbmysql-grp-by5kvszc.sql.tencentcdb.com',  # 我的IP地址
            port=25565,  # 不是字符串不需要加引号。
            user='root',
            password='iphone4S.',
            db='Cooperative_signature',
            charset='utf8'
        )
        cursor = conn.cursor()
        username = self.cilent.message_to_sm3_hash([username])
        password = self.cilent.message_to_sm3_hash([password])
        sql = 'select * from admin where username = "%s" and password="%s"' % (username, password)
        print(sql)
        res = cursor.execute(sql)
        print(res)
        cursor.close()
        conn.close()
        if res:
            self.response = True
            self.message[1] = username
            print('登录成功')
        else:
            self.response = False
            print('登录失败')

    def main_page(self):
        self.page2.pack(fill=X)

        start_connect_frame = ttk.Frame(self.page2)
        start_connect_button = ttk.Button(start_connect_frame, text="开始连接", command=self.connect)
        start_connect_button.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        connect_project_server = ttk.Radiobutton(start_connect_frame, text="协同签名服务器", variable=self.var,
                                                 value=8000)
        connect_project_server.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        connect_project_verify = ttk.Radiobutton(start_connect_frame, text="协同签名验证客户端", variable=self.var,
                                                 value=9000)
        connect_project_verify.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        start_connect_frame.pack(fill=X, padx=20, pady=5, side=TOP)

        message_box_labelframe = ttk.Labelframe(self.page2, text="交互信息")
        self.message_box_label = ScrolledText(message_box_labelframe, padding=5, height=13, autohide=True)
        self.message_box_label.pack(fill=X, padx=5, pady=5)
        message_box_labelframe.pack(fill=X, side=TOP, padx=20)

        private_key_labelframe = ttk.Labelframe(self.page2, text="客户端协同签名子私钥", width=450, height=50)
        private_key_label = ttk.Label(private_key_labelframe, textvariable=self.d1, wraplength=750)
        private_key_label.pack(fill=X, padx=2)
        private_key_labelframe.pack(fill=X, padx=20, side=TOP, pady=5)

        public_key_labelframe = ttk.Labelframe(self.page2, text="客户端协同签名公钥", width=450, height=50)
        public_key_label = ttk.Label(public_key_labelframe, textvariable=self.P1, wraplength=750)
        public_key_label.pack(fill=X, padx=2)
        public_key_labelframe.pack(fill=X, padx=20, side=TOP, pady=5)

        sign_rs_labelframe = ttk.Labelframe(self.page2, text="协同签名值RS", width=450, height=50)
        sign_rs_label = ttk.Label(sign_rs_labelframe, textvariable=self.RS, wraplength=750)
        sign_rs_label.pack(fill=X, padx=2)
        sign_rs_labelframe.pack(fill=X, padx=20, side=TOP, pady=5)

        control_button_frame_1 = ttk.Frame(self.page2)
        open_file_button = ttk.Button(control_button_frame_1, text="打开文件",
                                      command=self.open_file_page)
        open_file_button.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        create_key_button = ttk.Button(control_button_frame_1, text="协同秘钥",
                                       command=lambda: self.create_key(self.cilent, self.tcp_socket_1))
        create_key_button.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        create_sign_button = ttk.Button(control_button_frame_1, text="协同签名",
                                        command=lambda: self.create_sign(self.cilent, self.tcp_socket_1, self.message))
        create_sign_button.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        save_message_button = ttk.Button(control_button_frame_1, text="保存签名",
                                         command=self.save_file)
        save_message_button.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        send_sign_button = ttk.Button(control_button_frame_1, text="发送签名",
                                      command=lambda: self.send_verify(self.tcp_socket_1))
        send_sign_button.pack(side=LEFT, fill=X, expand=YES, padx=5, pady=5)
        control_button_frame_1.pack(fill=X, padx=20, pady=5, side=TOP)

    def open_file_page(self):
        top1 = ttk.Toplevel("打开文件")
        top1.minsize(600, 450)
        top1.attributes('-topmost', False)

        file_box_labelframe = ttk.Labelframe(top1, text="待签名文件内容摘要")
        self.file_box_label = ScrolledText(file_box_labelframe, padding=5, height=13, autohide=True)
        self.file_box_label.pack(fill=X, padx=5, pady=5)
        file_box_labelframe.pack(padx=20, side=TOP, pady=5)

        file_path_labelframe = ttk.Labelframe(top1, text="待签名文件路径")
        file_path_label = ttk.Label(file_path_labelframe, textvariable=self.filepath)
        file_path_label.pack(fill=X, padx=5, pady=5)
        file_path_labelframe.pack(fill=X, padx=20, side=TOP, pady=5)

        submit_button = ttk.Button(top1, text="打开文件", command=self.open_file)
        submit_button.pack(side=TOP, padx=10, pady=5)
        top1.mainloop()

    def connect(self):
        # 获取端口的连接信息
        port = self.var.get()
        print(f"端口:{port}")
        # 使用IPV4和TCP协议
        self.tcp_socket_1 = socket(AF_INET, SOCK_STREAM)
        # 设定ip和端口
        IP_PORT = ('127.0.0.1', port)
        # 绑定链接
        self.tcp_socket_1.connect(IP_PORT)
        t = time.gmtime()
        temp2 = (time.strftime("%Y-%m-%d %H:%M:%S", t))
        self.message_box_label.insert(END, temp2 + "\n")
        self.message_box_label.insert(END, f"客户端成功连接端口：{port}" + "\n")
        self.message_box_label.insert(END, "\n")

    def client_inter(self, typeid, tcp_socket_1, send_data="默认"):  # 当typeid的值为0时执行发送程序 当typeid值为1时执行接收程序
        if typeid == 0:
            while True:
                tcp_socket_1.send(send_data.encode("gbk"))
                from_server_msg = tcp_socket_1.recv(1024)
                if from_server_msg:
                    print(from_server_msg.decode("gbk"))
                    break
        elif typeid == 1:
            while True:
                flag = "client已收到消息"
                from_server_msg = tcp_socket_1.recv(1024)
                if len(from_server_msg) != 0:
                    temp1 = "客户端已接收参数信息：" + from_server_msg.decode("gbk")
                    t = time.gmtime()
                    temp2 = (time.strftime("%Y-%m-%d %H:%M:%S", t))
                    self.message_box_label.insert(END, temp2 + "\n")
                    self.message_box_label.insert(END, temp1 + "\n")
                    self.message_box_label.insert(END, "\n")

                    print(temp1)
                    tcp_socket_1.send(flag.encode("gbk"))
                    return from_server_msg.decode("gbk")

    def message_to_sm3_hash(self, message: list):
        string = ""
        for i in message:
            string = string + str(i)
        string = string.encode(encoding="utf-8")
        message_hash = sm3_hash(func.bytes_to_list(string))
        message_hash_bytes = message_hash.encode(encoding="utf-8")
        return message_hash_bytes

    def create_key(self, cilent, tcp):
        self.client_inter(send_data=str(self.message), typeid=0, tcp_socket_1=tcp)  # 发送数据0
        cilent.cilent_out_d1p1()
        p2 = self.client_inter(typeid=1, tcp_socket_1=tcp)  # 接收数据1
        cilent.cilent_out_P1(p2)
        self.client_inter(send_data=str(cilent.p1), typeid=0, tcp_socket_1=tcp)  # 发送数据2
        # 将label标签中的变量赋值
        self.d1.set(cilent.d1)
        self.P1.set(cilent.P1)

    def create_sign(self, cilent, tcp, message: list) -> str:
        cilent.message_to_sm3_hash(message)
        cilent.cilent_out_k1Q1()
        self.client_inter(send_data=str(cilent.Q1), typeid=0, tcp_socket_1=tcp)  # 发送数据3
        Q2 = self.client_inter(typeid=1, tcp_socket_1=tcp)  # 接收数据4
        c1 = int(self.client_inter(typeid=1, tcp_socket_1=tcp))  # 接收数据5
        cilent.cilent_out_r1s1(Q2=Q2, c1=c1)
        self.client_inter(send_data=str(cilent.s1), typeid=0, tcp_socket_1=tcp)  # 发送数据6
        s2 = int(self.client_inter(typeid=1, tcp_socket_1=tcp))  # 接收数据7
        c2 = int(self.client_inter(typeid=1, tcp_socket_1=tcp))  # 接收数据8
        RS = cilent.cilent_out_s(s2=s2, c2=c2)
        print(RS)
        self.RS.set(RS)

    def send_verify(self, tcp):  # 将待签名信息发送给签名验证客户端
        dict = {"message": self.message, "rs": self.cilent.RS, "public_key": self.cilent.P1}
        tcp.send(str(dict).encode("gbk"))

    def open_file(self):  # 打开待签名文件
        path = askopenfilename()
        if not path:
            return

        with open(path, encoding='utf-8') as f:
            self.message[0] = f.read()  # 将文件写入待签名消息列表
            print(self.message[0])
            self.file_box_label.insert(END, self.message[0])
            self.filepath.set(path)

    def save_file(self):  # 将源文件写入当前路径
        self.filename = '签名文件.txt'
        dict = {"message": self.message, "rs": self.cilent.RS, "public_key": self.cilent.P1}
        with open(self.filename, 'w') as file_object:
            file_object.write(str(dict))
        Messagebox.ok(title='保存签名', message='签名文件已经成功保存至软件相同路径!')


if __name__ == '__main__':
    # 绑定协同签名类
    cilent = CryptSM2()



    # 绑定窗口类
    root = ttk.Window("协同签名客户端", "yeti")
    ClientPage(root, cilent)
    root.mainloop()

